import { Component, OnInit, ViewChild, ElementRef, Renderer2 } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { fromEvent } from 'rxjs/observable/fromEvent';
import { map } from 'rxjs/operators';

import { Store } from '@ngrx/store';
import { 
  FoldingState, 
  SetLayers, 
  SetResourceTree, 
  foldingSelector 
} from '../../../../store';
import { 
  ResourceTreeState, 
  LoadProfessional, professionalSelectors,
  LoadOwn, ownSelectors,
  LoadPublic, publicSelectors 
} from '../../store';

import { SideComponentParams } from '../../../side-component-container/side-component-params';
import { TreeviewItem, TreeviewConfig, TreeItem } from '../../components';
import { Folding } from '../../../../models';

import { State } from '../../../../../store';
import { LoadLayer } from '../../../../store/actions/layers.action';
import * as fromLayersSelector from '../../../../store/selectors/layer.selector';

@Component({
  selector: 'ege-resource-tree',
  templateUrl: './resource-tree.component.html',
  styleUrls: ['./resource-tree.component.scss']
})
export class ResourceTreeComponent implements OnInit {

  professional$: Observable<TreeviewItem[]>;
  own$: Observable<TreeviewItem[]>;
  public$: Observable<TreeviewItem[]>;
  treeviewConfig: TreeviewConfig;

  @ViewChild('tabsNavs') tabsNavs: ElementRef;
  @ViewChild('tabsContent') tabsContent: ElementRef;

  layerFolding: Folding;
  resourceTreeFolding: Folding;

  messages: 'pushing'|'pushed'|'error';
  added: string[] = [];


  constructor(
    private store: Store<State>,
    private params: SideComponentParams,
    private renderer: Renderer2
  ) { }

  ngOnInit() { 
    this.bindEventToTabsNavs();
    this.activeTabs(0);
    this.loadTreeviews();
    this.treeviewConfig = this.initialTreeviewConfig();
    this.professional$ = this.store.select(professionalSelectors.getAllProfessionalsToTreeview);
    this.own$ = this.store.select(ownSelectors.getAllOwnsToTreeview);
    this.public$ = this.store.select(publicSelectors.getAllPublicsToTreeview);
    this.store.select(fromLayersSelector.getAllLayerIds)
      .subscribe((ids: string[]) => this.added = ids);
    this.store.select(foldingSelector.getFoldingLayers)
      .subscribe((folding: Folding) => this.layerFolding = folding);
    this.store.select(foldingSelector.getFoldingResourceTree)
      .subscribe((folding: Folding) => {
        this.resourceTreeFolding = folding;
        if(folding && !folding.visible) {
          this.params.onClose();
        }
      });
    this.pushMessage();
  }

  onClickRoot(event): void {
    event.stopPropagation();
  }

  bindEventToTabsNavs(): void {
    const target: any = this.tabsNavs.nativeElement.querySelectorAll('li');
    fromEvent(target, 'click')
      .pipe(
        map((event: any) => Array.prototype.indexOf.call(target, event.target))
      )
      .subscribe((index: number) => {
        this.activeTabs(index);
      });
  }

  activeTabs(index: number): void {
    this.renderer.setStyle(this.tabsContent.nativeElement, 'margin-left', `-${index*100}%`);
    this.activeTabsNav(index);
    this.activeTabsContent(index);
  }

  activeTabsNav(index: number): void {
    const navs: any[] = this.tabsNavs.nativeElement.querySelectorAll('li');
    navs.forEach((nav, _index) => {
      if(_index === index) {
        this.renderer.addClass(nav, 'tabs-nav-active');
      } else {
        this.renderer.removeClass(nav, 'tabs-nav-active');
      }
    });
  }

  activeTabsContent(index: number): void {
    const contents: any[] = this.tabsContent.nativeElement.querySelectorAll('.resource-tree-tabs-tabpane');
    contents.forEach((content, _index) => {
      if(_index === index) {
        this.renderer.addClass(content, 'tabs-tabpane-active');
      } else {
        this.renderer.removeClass(content, 'tabs-tabpane-active');
      }
    });
  }

  onCollapse(): void {
    this.params.onClose();
    this.store.dispatch(new SetResourceTree({ ...this.resourceTreeFolding, visible: false }));
  }

  loadTreeviews(): void {
    this.store.select(professionalSelectors.getProfessionalLoaded)
      .subscribe((loaded: boolean) => !loaded && this.store.dispatch(new LoadProfessional()));
    this.store.select(ownSelectors.getOwnLoaded)
      .subscribe((loaded: boolean) => !loaded && this.store.dispatch(new LoadOwn()));
    this.store.select(publicSelectors.getPublicLoaded)
      .subscribe((loaded: boolean) => !loaded && this.store.dispatch(new LoadPublic())); 
  }

  onPlus(treeviewItem: TreeviewItem): void {
    const value: any = treeviewItem.value;
    this.store.dispatch(new LoadLayer([value.id]));
    this.store.dispatch(new SetLayers({ ...this.layerFolding, visible: true}));
  }

  onPushGroup(treeviewItem: TreeviewItem): void {
    const allNodes: any[] = this.serializeTreeview([treeviewItem]);
    const ids = allNodes.map(node => node.id);
    this.store.dispatch(new LoadLayer(ids))
    this.store.dispatch(new SetLayers({ ...this.layerFolding, visible: true}));    
  }

  private initialTreeviewConfig(): TreeviewConfig {
    return TreeviewConfig.create({
      hasAllCheckBox: false,
      hasFilter: true,
      hasCollapseExpand: false,
      hasCheckBox: false
    });
  }

  private serializeTreeview(treeviewItems: TreeviewItem[]): any[] {
    let allNodes: any[] = [];
    treeviewItems.forEach((treeviewItem: TreeviewItem) => {
      let nodes: any[] = [];
      if(treeviewItem.children) {
        nodes = this.serializeTreeview(treeviewItem.children);
      } else {
        nodes = [treeviewItem.value];
      }
      allNodes = [...allNodes, ...nodes];
    });
    return allNodes;
  }

  private pushMessage(): void {
    this.store.select(fromLayersSelector.getLayerLoading).subscribe(loading => {
      if(loading) {
        this.messages = 'pushing';
      }
    });
    this.store.select(fromLayersSelector.getLayerLoaded).subscribe(loaded => {
      if(loaded) {
        this.messages = 'pushing';
        setTimeout(() => this.messages = null, 500);
      }
    });
    this.store.select(fromLayersSelector.getLayerLoadError).subscribe(loadError => {
      if(loadError) {
        this.messages = 'pushing';
        setTimeout(() => this.messages = null, 500);
      }
    });
  }

}
